use super::{Result, APP_CONFIG_NODE_PATH};
use crate::config::cmd_arg;
use etcd_manager_util::common::{NodeChangeType, NodeValueModel};
use log_util;
use serde::{Deserialize, Serialize};
use std::sync::{Arc, RwLock};
use string_util::string_error::StringErrorBuilder;

lazy_static::lazy_static! {
  static ref APP_CONFIG:RwLock<Arc<AppConfig>>={
        RwLock::new(Arc::new(AppConfig::default()))
    };
}

crate::config_handler! {AppConfig}

/// app配置
#[derive(Serialize, Deserialize)]
pub struct AppConfig {
    /// 是否加载成功
    #[serde(skip)]
    pub is_error: bool,
    /// 监听地址
    #[serde(rename(serialize = "HttpListenAddr"))]
    pub http_listen_addr: String,
}

impl AppConfig {
    pub fn node_path() -> String {
        format!(
            "{}{}",
            APP_CONFIG_NODE_PATH,
            &cmd_arg::get_cmd_arg().app_node
        )
    }

    pub fn weight() -> u32 {
        u32::MAX
    }

    #[allow(unused)]
    pub fn module_name() -> &'static str {
        "AppConfig"
    }

    pub fn load(_change_type: NodeChangeType, val: &NodeValueModel) -> Result {
        let mut err = StringErrorBuilder::new("AppConfig");

        // 加载
        let result: serde_json::Result<AppConfig> = serde_json::from_str(val.value.as_str());
        let mut config_obj;
        match result {
            Ok(val) => config_obj = val,
            Err(inner_err) => {
                return err
                    .append(format!("Deserialize err:{:?}", inner_err).as_str())
                    .to_result()
            }
        }

        // check
        if config_obj.http_listen_addr.is_empty() {
            err.append("http_listen_addr need be set");
        }

        config_obj.is_error = err.is_error();
        if config_obj.is_error {
            return err.to_result();
        }

        {
            let mut writer = APP_CONFIG.write().unwrap();
            *writer = Arc::new(config_obj);
        }

        err.to_result()
    }
}

impl Default for AppConfig {
    fn default() -> Self {
        AppConfig {
            http_listen_addr: "".to_string(),
            is_error: true,
        }
    }
}

impl Clone for AppConfig {
    fn clone(&self) -> Self {
        AppConfig {
            is_error: self.is_error,
            http_listen_addr: self.http_listen_addr.clone(),
        }
    }
}

#[allow(unused)]
pub fn get_app_config() -> Arc<AppConfig> {
    let reader = APP_CONFIG.read().unwrap();
    reader.clone()
}
